# coding=utf-8
# author=haishan09@gmail.com
import json
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render
from django.views.generic import View 
from treemenu.models import MenuItem
from cube.models import Cube
from chart.models import Chart
from report.models import Report, CubeShip
from report.forms import CutsForm, CubeShipForm, \
        DrilldownFormSet, CutFormSet, AggregateFormSet, \
        OrderByFormSet, ChartConfigForm
from common.provider import provider_manager


class ThemeView(View):

    def get(self, request, theme_id=None, **kwargs):
        root_menuitem = MenuItem.objects.get(pk=theme_id)
        context = {'root_menuitem': root_menuitem, 'theme_id': theme_id}
        return render(request, 'report/theme.html', context)


class ReportView(View):

    def get(self, request, theme_id=None, report_id=None, **kwargs):
        report = Report.objects.get(pk=report_id)
        cuts_form = CutsForm(report)
        context = {'report': report, 'theme_id': theme_id, 'cuts_form': cuts_form}
        return render(request, 'report/detail.html', context)


class DrilldownFormSetTemplate(View):

    def get(self, request, **kwargs):
        cube = None
        cube_id = request.GET.get('cube_id')
        if cube_id:
            cube = Cube.objects.get(pk=cube_id)
        formset = DrilldownFormSet(form_kwargs={'cube': cube}, prefix='drilldown')
        return HttpResponse('\n'.join('<div class="drilldown-formset">' + f.as_table() + '</div>' for f in formset.forms))

class CutFormSetTemplate(View):

    def get(self, request, **kwargs):
        cube = None
        cube_id = request.GET.get('cube_id')
        if cube_id:
            cube = Cube.objects.get(pk=cube_id)
        formset = CutFormSet(form_kwargs={'cube': cube}, prefix='cut')
        return HttpResponse('\n'.join('<div class="cut-formset">' + f.as_table() + '</div>' for f in formset.forms))

    def post(self, request, **kwargs):
        cube = None
        cube_id = request.POST.get('cube')
        if cube_id:
            cube = Cube.objects.get(pk=cube_id)
        formset = CutFormSet(request.POST, form_kwargs={'cube': cube}, prefix='cut')
        return HttpResponse('\n'.join('<div class="cut-formset">' + f.as_table() + '</div>' for f in formset.forms))

class AggregateFormSetTemplate(View):

    def get(self, request, **kwargs):
        cube = None
        chart = None
        cube_id = request.GET.get('cube_id')
        chart_id = request.GET.get('chart_id')
        if cube_id:
            cube = Cube.objects.get(pk=cube_id)
        if chart_id:
            chart = Chart.objects.get(pk=chart_id)
        formset = AggregateFormSet(form_kwargs={'cube': cube, 'chart': chart}, prefix='aggregate')
        return HttpResponse('\n'.join('<div class="aggregate-formset">' + f.as_table() + '</div>' for f in formset.forms))

    def post(self, request, **kwargs):
        cube = None
        chart = None
        cube_id = request.POST.get('cube')
        chart_id = request.POST.get('chart')
        if cube_id:
            cube = Cube.objects.get(pk=cube_id)
        if chart_id:
            chart = Chart.objects.get(pk=chart_id)
        formset = AggregateFormSet(request.POST, form_kwargs={'cube': cube, 'chart': chart}, prefix='aggregate')
        return HttpResponse('\n'.join('<div class="aggregate-formset">' + f.as_table() + '</div>' for f in formset.forms))

class OrderByFormSetTemplate(View):

    def get(self, request, **kwargs):
        cube = None
        cube_id = request.GET.get('cube_id')
        if cube_id:
            cube = Cube.objects.get(pk=cube_id)
        formset = OrderByFormSet(form_kwargs={'cube': cube}, prefix='orderby')
        return HttpResponse('\n'.join('<div class="orderby-formset">' + f.as_table() + '</div>' for f in formset.forms))

    def post(self, request, **kwargs):
        cube = None
        cube_id = request.POST.get('cube')
        if cube_id:
            cube = Cube.objects.get(pk=cube_id)
        formset = OrderByFormSet(request.POST, form_kwargs={'cube': cube}, prefix='orderby')
        return HttpResponse('\n'.join('<div class="orderby-formset">' + f.as_table() + '</div>' for f in formset.forms))

class ChartConfigFormTemplate(View):

    def get(self, request, **kwargs):
        chart = None
        initial = None
        chart_id = request.GET.get('chart_id')
        if chart_id:
            chart = Chart.objects.get(pk=chart_id)
            initial = {'config': chart.dconf}
        return HttpResponse(ChartConfigForm(chart=chart, prefix='chart', initial=initial).as_table())

class CubeShipConfGenMixin(object):

    def get_context_and_config(self, data=None, cube=None, chart=None, config=None):
        if not config:
            config = {
                'drilldowns': [],
                'cuts': [],
                'aggregates': [],
                'orderbys': [],
                'chart': chart and chart.dconf or {}
            }
        args = (data, )
        kwargs = {
            'prefix': 'drilldown', 
            'form_kwargs': {'cube': cube}, 
            'initial': config.get('drilldowns', [])
        }
        drilldown_formset = DrilldownFormSet(*args, **kwargs)
        if drilldown_formset.is_valid():
            drilldowns = []
            for form in drilldown_formset:
                drilldown = form.cleaned_data.get('drilldown')
                rank = form.cleaned_data.get('rank', 0)
                if drilldown:
                    drilldowns.append({'drilldown': drilldown, 'rank': rank})
            config['drilldowns'] = sorted(drilldowns, key=lambda d: d['rank'])
        kwargs = {
            'prefix': 'cut', 
            'form_kwargs': {'cube': cube}, 
            'initial': config.get('cuts', [])
        }
        cut_formset = CutFormSet(*args, **kwargs)
        if cut_formset.is_valid():
            cuts = []
            for form in cut_formset:
                cut = form.cleaned_data.get('cut')
                condition = form.cleaned_data.get('condition')
                value = form.cleaned_data.get('value')
                rank = form.cleaned_data.get('rank', 0)
                if cut and condition:
                    cuts.append({
                        'cut': cut, 
                        'condition': condition, 
                        'value': value, 
                        'rank': rank})
            config['cuts'] = sorted(cuts, key=lambda c: c['rank'])
        kwargs = {
            'prefix': 'aggregate', 
            'form_kwargs': {'cube': cube, 'chart': chart}, 
            'initial': config.get('aggregates', [])
        }
        aggregate_formset = AggregateFormSet(*args, **kwargs)
        if aggregate_formset.is_valid():
            aggregates = []
            for form in aggregate_formset:
                aggregate = form.cleaned_data.get('aggregate')
                yaxis_index = form.cleaned_data.get('yaxis_index')
                chart_type = form.cleaned_data.get('chart_type')
                expression = form.cleaned_data.get('expression')
                stack = form.cleaned_data.get('stack')
                rank = form.cleaned_data.get('rank', 0)
                if aggregate:
                    aggregates.append({'aggregate': aggregate, 
                                       'yaxis_index': yaxis_index, 
                                       'chart_type': chart_type, 
                                       'expression': expression, 
                                       'stack': stack, 
                                       'rank': rank})
            config['aggregates'] = sorted(aggregates, key=lambda a: a['rank'])
        kwargs = {
            'prefix': 'orderby', 
            'form_kwargs': {'cube': cube}, 
            'initial': config.get('orderbys', [])
        }
        orderby_formset = OrderByFormSet(*args, **kwargs)
        if orderby_formset.is_valid():
            orderbys  = []
            for form in orderby_formset:
                order_by  = form.cleaned_data.get('order_by')
                order = form.cleaned_data.get('order')
                rank = form.cleaned_data.get('rank', 0)
                if order_by and order:
                    orderbys.append({'order_by': order_by, 'order': order, 'rank': rank})
            config['orderbys'] = sorted(orderbys, key=lambda a: a['rank'])
        kwargs = {
            'prefix': 'chart',
            'chart': chart, 
            'initial': {'config': config['chart']}
        }
        chartconfig_form = ChartConfigForm(data, **kwargs)
        if chartconfig_form.is_valid():
            config['chart'] = json.loads(chartconfig_form.cleaned_data['config'])
        context = {
            'drilldown_formset': drilldown_formset,
            'cut_formset': cut_formset,
            'aggregate_formset': aggregate_formset,
            'orderby_formset': orderby_formset,
            'chartconfig_form': chartconfig_form
        }
        return context, config


class CubeShipManager(View, CubeShipConfGenMixin):
    
    def get(self, request, cubeship_id=None, **kwargs):
        cubeship = None
        cube = None
        config = None
        chart = None
        if cubeship_id:
            cubeship = CubeShip.objects.get(pk=cubeship_id)
            cube = cubeship.cube
            config = cubeship.dconf
            chart = cubeship.chart
        context, config = self.get_context_and_config(cube=cube, chart=chart, config=config)
        context.update({
            'chart': chart,
            'cubeship': cubeship,
            'cubeship_form': CubeShipForm(instance=cubeship),
        })
        return render(request, 'report/manager/cubeship.html', context)

    def post(self, request, cubeship_id=None, **kwargs):
        cubeship = None
        if cubeship_id:
            cubeship = CubeShip.objects.get(pk=cubeship_id)
            cube = cubeship.cube
            chart = cubeship.chart
        cubeship_form = CubeShipForm(request.POST, instance=cubeship)
        if cubeship_form.is_valid():
            cube = cubeship_form.cleaned_data['cube']
            chart = cubeship_form.cleaned_data['chart']
            instance = cubeship_form.save(commit=False)
        context, config = self.get_context_and_config(data=request.POST, cube=cube, chart=chart)
        instance.config = config
        instance.save()
        context.update({
            'chart': chart,
            'cubeship': cubeship,
            'cubeship_form': CubeShipForm(instance=instance),
        })
        return render(request, 'report/manager/cubeship.html', context)

class CubeShipGetConfig(View, CubeShipConfGenMixin):

    def post(self, request, cubeship_id=None, **kwargs):
        cube = None
        chart = None
        limit = 0
        cubeship_form = CubeShipForm(request.POST)
        if cubeship_form.is_valid():
            cube = cubeship_form.cleaned_data['cube']
            chart = cubeship_form.cleaned_data['chart']
            limit = cubeship_form.cleaned_data['limit']
        _, config = self.get_context_and_config(data=request.POST, cube=cube, chart=chart)
        config['limit'] = limit
        for k, v in config['chart'].items():
            config['chart'][k] = (v != 'null' and v or None)
        config['name_label_dict'] = {}
        if cube:
            for dim in cube.dimensions.all():
                config['name_label_dict'][dim.name] = dim.label
            for agg in cube.aggregates.all():
                config['name_label_dict'][agg.name] = agg.label
        return JsonResponse(config, safe=False)

class CubeShipGetData(View, CubeShipConfGenMixin):

    def post(self, request, **kwargs):
        cube = None
        chart = None
        cubeship_form = CubeShipForm(request.POST)
        limit = 0 
        offset = 0
        if cubeship_form.is_valid():
            cube = cubeship_form.cleaned_data['cube']
            chart = cubeship_form.cleaned_data['chart']
            limit = cubeship_form.cleaned_data['limit']
        _, config = self.get_context_and_config(request.POST, cube=cube, chart=chart)
        if request.POST.get('iDisplayStart'):
            offset = int(request.POST.get('iDisplayStart'))
        if request.POST.get('iDisplayLength'):
            limit = int(request.POST.get('iDisplayLength'))
        if request.POST.get('iSortCol_0'):
            order_by_able = [d['drilldown'] for d in config['drilldowns']] + [a['aggregate'] for a in config['aggregates']]
            order_by = order_by_able[int(request.POST.get('iSortCol_0'))]
            order = request.POST.get('sSortDir_0')
            config['orderbys'] = [{'order_by': order_by, 'order': order}]
        provider = cube.provider.get_instance()
        config['cube'] = cube
        config['limit'] = limit
        config['offset'] = offset
        adapter_cls = provider_manager.get_provider('chartadapter', chart.name)
        retdict = adapter_cls().transform(config, provider.request(config))
        return JsonResponse(retdict, safe=False)

